import json
import re

from django.http import JsonResponse
from django.views import View

# 注意User的导包路径
from django_redis import get_redis_connection
from rest_framework.generics import CreateAPIView

from apps.carts.utils import merge_cart_cookie_to_redis
from apps.goods.models import SKU
from apps.users.models import User, Address
from django.contrib.auth import login, logout
from django.contrib.auth import authenticate

from apps.users.serializers import UserInfoSerializer, UserSerializer
from meiduo_mall.settings.dev import logger
from meiduo_mall.utils.views import LoginRequiredJSONMixin
from meiduo_mall.utils.secret import SecretOauth


"""
判断用户名是否重复注册借口文档：
    路由：　　　　　　/usernames/<username:username>/
    请求方式：  　　　GET
    参数(路径参数)：　username  string  必传　　用户名
              
    响应结果(json)：　code  状态码　　400是失败，0是成功
    　　　　　　　　　errmsg   提示信息
    　　　　　　　　　count    返回用户名个数

"""
class UsernameCountView(View):
    """判断用户名是否重复注册"""

    def get(self, request, username):
        '''判断用户名是否重复'''
        # 1.查询username在数据库中的个数
        try:
            count = User.objects.filter(username=username).count()
        except Exception as e:
            return JsonResponse({'code':400, 'errmsg':'访问数据库失败'})

        # 2.返回结果(json) ---> code & errmsg & count
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'count':count})


"""
手机号重复注册接口文档：
    请求路径     　/mobiles/<mobile:mobile>/count
    
    请求方式       GET
    
    参数(路径参数)  参数名：mobile 
                 类型：string
                 是否必传：是
                 说明：手机号
                 
    响应          类型：JSON
                  code: 状态码，０代表成功；４００代表失败
                  errmsg:  提示信息
                  count:   记录该手机号的个数
    
"""
class  MobileCountView(View):
    # 接收参数
    def get(self, request, mobile):
        try:
            # 查询mobile在数据库中的个数
            count = User.objects.filter(mobile=mobile).count()

        except Exception as e:
            return JsonResponse({'code':400, 'errmsg':'查询数据库出错'})
        # 返回结果
        return JsonResponse({'code':0, 'errmsg':'ok', 'count':count})



"""
用户注册功能实现：
    路径：　　　　/register/
    请求方式：   POST
    参数(json)：　　　  username：类型是string，必传，说明是用户名
                password: 类型是string,必传，说明是密码
                password2:　类型是string，必传，说明是确认密码
                mobile:　类型是string，必传，说明是手机号
                sms_code:　类型是string，必传，说明是验证码
                allow:　类型是bool，必传，说明是用户名是否同意用户协议     
                 
    响应：　    code是状态码，０是成功，４００是失败
    　　　　    errmsg:提示信息    
"""
class RegisterView(View):
    def post(self,request):
        # 1,接收参数，请求体中的ｊｓｏｎ数据
        json_dict = json.loads(request.body.decode())

        # 2,解析参数
        username = json_dict.get('username')
        password = json_dict.get('password')
        password2 = json_dict.get('password2')
        mobile = json_dict.get('mobile')
        allow = json_dict.get('allow')
        sms_code = json_dict.get('sms_code')

        # 3,校验参数
        # 3.1 判断是否为空
        if not all([username, password, password2, mobile, allow, sms_code]):
            return JsonResponse({'code':400, 'errmsg':'缺少必传参数'})

        # 3.2　正则校验：用户名
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return JsonResponse({'code':400, 'errmsg':'用户名格式不正确'})

        # 3.3　正则校验：密码
        if not re.match(r'^[a-zA-Z0-9_-]{8,20}$', password):
            return JsonResponse({'code':400, 'errmsg':'密码格式不正确'})

        # 3.4　正则校验：手机号
        if not re.match('1[3-9]\d{9}', mobile):
            return JsonResponse({'code':400, 'errmsg':'手机号格式不正确'})

        # 3.5　判断密码是否一致
        if password != password2:
            return JsonResponse({'code':400, 'errmsg':'两次密码输入不匹配'})

        # 3.6　判断是否勾选协议同意
        if allow != True:
            return JsonResponse({'code':400, 'errmsg':'没有勾选用户协议'})

        # 判断短信验证码是否正确，跟图形验证码的逻辑是一样的
        # 首先接收前端短信验证码　sms_code = json_dict.get('sms_code')
        # 然后获取后台短信验证码
        redis_conn = get_redis_connection('verify_code')
        sms_code_server = redis_conn.get('sms_%s' % mobile)
        # 校验前端和后台短信验证码
        if not sms_code_server:
            return JsonResponse({'code': 400, 'errmsg': '短信验证码过期了'})
        if sms_code != sms_code_server.decode():
            return JsonResponse({'code': 400, 'errmsg': '短信验证码有误'})

        # 4,主核心思路：user增加
        try:
            user = User.objects.create_user(username=username, password=password, mobile=mobile)
        except Exception as e:
            return JsonResponse({'code':400, 'errmsg':'注册失败'})

        # 保持登录状态
        login(request, user)


        # 5,返回json
        response = JsonResponse({'code': 0, 'errmsg': '注册成功'})
        # 合并购物车
        merge_cart_cookie_to_redis(request=request, response=response)
        response.set_cookie('username', user.username, max_age=24 * 14 * 3600)
        return response


"""
用户登录借接口文档＂
    路由：　　　login/
    请求方式：  POST
    参数：请求体(json)  username  string  必传　　用户名
    　　　　　　　　　　　password  string  必传　　密码
    　　　　　　　　　　　remembered　bool  必传　是否记住登录
    响应结果：json   code　　状态码　　0是成功　　　400是失败
                   errmsg  提示信息
"""
class LoginView(View):

    def post(self, request):
        # 1, 接收参数, 提取参数
        json_dict = json.loads(request.body.decode())
        username = json_dict.get('username')
        password = json_dict.get('password')
        remembered = json_dict.get('remembered')

        # 2，校验参数(判空)
        if not all([username, password]):
            return JsonResponse({'code':400, 'errmsg':'参数不齐'})

        # 多账号登录
        # if re.match(r'^1[3-9]\d{9}$', username):
        #     User.USERNAME_FIELD = 'mobile'
        # else:
        #     User.USERNAME_FIELD = 'username'


        # 3， 与数据库进行判断，看用户名和密码是否一致，认证是否能够登录－－authenticate(密码会加密)
        user = authenticate(request, username=username, password=password)
        if user is None:
            return JsonResponse({'code': 400, 'errmsg': '用户名或密码错误'})

        # 4，保持回话状态
        login(request, user)

        # 5,是否记住登录
        if remembered != True:
            request.session.set_expiry(0)
        else:
            request.session.set_expiry(None)

        # 6,返回响应结果
        response = JsonResponse({'code': 0, 'errmsg': '登录成功'})
        # 合并购物车
        merge_cart_cookie_to_redis(request=request, response=response)
        response.set_cookie('username', user.username, max_age=24 * 14 * 3600)
        return response



""" 退出登录"""
class LogoutView(View):
    def delete(self, request):

        # 1.清除session
        logout(request)

        # 2.清除cookie--username
        response = JsonResponse({'code':0, 'errmsg':'退出成功!'})
        response.delete_cookie('username')

        # 3.返回
        return response


"""
个人中心页面展示接口文档：
    路由：　　　　info/
    请求方式：   GET
    参数：       无参数
    响应结果：json　　code       状态码　　400失败　　0成功
                    errmsg　　　提示信息
                    info_data:　返回给前端数据的字典
{
     "code":0,
     "errmsg":"ok",
     "info_data":{
           "username":"zs",
           "mobile": "15144556677",
           "email": "12344566@qq.com",
           "email_active": 'true'
     }
}

"""
class UserInfoView(LoginRequiredJSONMixin, View):
    # 用户中心
    # def get(self, request):
    #     info_data =  {
    #             "username": request.user.username,
    #             "mobile": request.user.mobile,
    #             "email": request.user.email,
    #             "email_active": request.user.email_active
    #         }
    #     return JsonResponse({
    #         'code': 0,
    #         'errmsg': 'ok',
    #         "info_data":info_data
    #     })

    def get(self, request):
        user = request.user
        serializer = UserInfoSerializer(instance=user)
        data = serializer.data
        return JsonResponse({'code':0, 'errmsg': 'ok', 'info_data':data})




"""
添加邮箱借口文档：
    路由：　　　　eamils/
    请求方式：   put
    参数：json   email  string  必传　　邮箱
    响应结果：json  code和errmsg

"""
# 添加邮箱
class EmailView(LoginRequiredJSONMixin, View):
    def put(self, request):
        # 3.接收参数 email 校验 email正则
        json_dict = json.loads(request.body.decode())
        email = json_dict.get('email')

        # 4.修改User类 request.user.email = new_email
        request.user.email = email
        request.user.save()

        # 发邮件
        from apps.users.utils import generate_verify_email_url
        verify_url = generate_verify_email_url(request)
        from celery_tasks.email.tasks import send_verify_email
        send_verify_email.delay(email, verify_url)

        # 5. request.user.save()
        # 6.返回结果
        return JsonResponse({'code': 0, 'errmsg': 'OK'})


class VerifyEmailView(View):
    def put(self, request):
        # - 1.接收 token
        token = request.GET.get('token')

        if not token:
            return JsonResponse({'code': 400, 'errmsg': 'token缺少'})

        # - 2.解密
        data_dict = SecretOauth().loads(token)

        # - 4.去数据库对比 user_id,email
        try:
            user = User.objects.get(pk=data_dict.get('user_id'), email=data_dict.get('email'))
        except Exception as e:
            print(e)
            return JsonResponse({'code': 400, 'errmsg': '参数有误!'})

        # - 5.修改激活状态
        try:
            user.email_active = True
            user.save()
        except Exception as e:
            return JsonResponse({'code': 0, 'errmsg': '激活失败!'})


        return JsonResponse({'code': 0, 'errmsg': '激活成功!'})


class CreateAddressView(LoginRequiredJSONMixin, View):
    def post(self, request):

        # 1.接收参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 2.校验参数  -判空 --判正则

        # 3.增加
        try:
            address = Address.objects.create(
                user=request.user,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,

                title=receiver,
                receiver=receiver,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email

            )

            # 判断用户  是否 设置 默认 地址
            if not request.user.default_address:
                request.user.default_address= address
                request.user.save()

        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '增加失败!'})

        # 4.address == >address_dict
        address_dict = {
            "id": address.id,
            "title":address.title ,
            "receiver": address.receiver,

            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,

            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        return JsonResponse({'code': 0, 'errmsg': '增加成功!', 'address':address_dict})


class AddressView(View):
    """用户收货地址"""

    def get(self, request):
        """提供地址管理界面
        """
        # 获取所有的地址:
        addresses = Address.objects.filter(user=request.user,  is_deleted=False)

        # 创建空的列表
        address_dict_list = []
        # 遍历
        for address in addresses:
            address_dict = {
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            }
            address_dict_list.append(address_dict)

        return JsonResponse({'code':0,'errmsg':'ok','addresses':address_dict_list,'default_address_id':request.user.default_address_id})


class UpdateDestroyAddressView(View):
    """
    修改收货地址的接口文档：
        路径：　　　/address/(?P<address_id>\d+)/
        请求方式： PUT
        参数：路径参数和json　　　address_id　string  必传　路径参数－要修改的地址ＩＤ
                  receiver    string  必传  收货人
                  province_id string  必传　　省份ＩＤ
                  city_id     string  必传　　　城市ｉｄ
                  district_id string  必传　　　区县ｉｄ
                  place       string  必传     收货地址
                  mobile      string  必传　　　手机号
       -           tel         string  不是必传　固定电话
                  email       string  不是必传　邮箱
        响应结果：json　　code  errmsg   id(地址id)  receiver  province
                        city  district  place  mobile tel eamil
    """
    def put(self, request, address_id):
        # １，　接收参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # ２，校验参数（判空，正则）
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 400, 'errmsg':'缺少必传参数'})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400,
                                      'errmsg': '参数mobile有误'})

        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return JsonResponse({'code': 400,
                                          'errmsg': '参数tel有误'})
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return JsonResponse({'code': 400,
                                          'errmsg': '参数email有误'})

        # ３，判断地址是否存在，并更新地址信息
        try:
            Address.objects.filter(id=address_id).update(
                user = request.user,
                title = receiver,
                receiver = receiver,
                province_id = province_id,
                city_id = city_id,
                district_id = district_id,
                place = place,
                mobile = mobile,
                tel = tel,
                email = email
            )
        except Exception as e :
            logger.error(e)
            return JsonResponse({'code':400,'errmsg':'更新地址失败'})

        # ４，构造响应数据
        address = Address.objects.get(id=address_id)
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        # ５，返回响应结果
        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'address': address_dict
        })


    """
    删除收货地址接口文档：
        路由：　　　　/address/(?P<address_id>\d+)/
        请求方式：　　DELETE
        参数：路径参数　　address_id  string 必传　要修改的地址id
        响应结果：　　code  errmsg   　
    """
    def delete(self, request, address_id):
        try:
            address = Address.objects.get(id=address_id)
            address.is_deleted=True
            address.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code':400, 'errmsg':'删除地址失败'})

        # 响应结果
        return JsonResponse({'code':0, 'errmsg':'删除地址成功'})



"""
设置默认地址接口文档：
    路由：　　　addresses/<int:address_id>/default/
    请求方式：　PUT
    参数：     address_id
    响应结果：  code errmsg
"""
class DefaultAddressView(View):
    def put(self, request, address_id):
        try:
            # 接收参数，获取查询地址
            address = Address.objects.get(id=address_id)
            # 设置地址为默认
            request.user.default_address = address
            request.user.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '设置默认地址失败'})

        # 返回响应结果
        return JsonResponse({'code': 0, 'errmsg': '设置默认地址成功'})




"""
修改地址标题接口文档：
    路由：　　　addresses/<int:address_id>/title/
    请求方式：　PUT
    参数：　路径参数－address_id　　　json-title
    响应结果：json  code errmsg
"""
class UpdateTitleAddressView(View):
    def put(self, request, address_id):
        # 接收参数
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')

        try:
            address = Address.objects.get(id=address_id)
            # 设置新的地址标题
            address.title = title
            address.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '修改地址标题失败'})

        # 返回响应结果
        return JsonResponse({'code': 0, 'errmsg': '修改地址标题成功'})



"""
修改密码接口文档：
    路由：　　　/password/
    请求方式： PUT
    参数：json    old_password  new_password   new_password2  
    响应结果：json    code  errmsg
"""
class ChangePasswordView(LoginRequiredJSONMixin,View):
    def put(self, request):
        # 接收参数
        json_dict = json.loads(request.body.decode())
        old_password = json_dict.get('old_password')
        new_password = json_dict.get('new_password')
        new_password2 = json_dict.get('new_password2')

        # 校验参数
        if not all([old_password, new_password, new_password2]):
            return JsonResponse({'code':400, 'errmsg':'缺少必传参数'})

        result = request.user.check_password(old_password)
        if not result:
            return JsonResponse({'code': 400, 'errmsg': '原始密码不正确'})

        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return JsonResponse({'code': 400, 'errmsg': '新密码的格式不正确'})

        if new_password != new_password2:
            return JsonResponse({'code': 400, 'errmsg': '两次输入的密码不一致'})

        # 修改密码
        try:
            request.user.set_password(new_password)
            request.user.save()
            print('成功')
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '修改密码失败'})


        # 清理状态保持信息
        logout(request)

        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        response.delete_cookie('username')

        # 返回响应结果
        return response



class UserBrowseHistory(LoginRequiredJSONMixin, View):
    """
    增加浏览记录接口文档:
        路由：　　　/browse_histories/
        请求方式：  POST
        参数： json    sku_id
        响应结果：json    code  errmsg
    """
    def post(self, request):
        # 1.接收参数
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')

        # 2.校验参数
        try:
            SKU.objects.get(pk=sku_id)
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': 'sku不存在'})

        # 3.redis--pipeline--lrem --lpush --ltrim --execute
        # list user.id:[1, 2 ,3]
        client = get_redis_connection('history')
        save_key = 'history_%s' % request.user.id
        p1 = client.pipeline()
        # 去重
        p1.lrem(save_key, 0, sku_id)
        # 插入
        p1.lpush(save_key, sku_id)
        # 切片
        p1.ltrim(save_key, 0,4)
        p1.execute()

        # 4.返回响应对象
        return JsonResponse({'code': 0, 'errmsg': '记录成功!'})


    """
    查询用户浏览记录接口文档：
        路由：　　　　/browse_histories/
        请求方式：　　GET
        参数:　　　　
        响应结果： code  errmsg  skus[]
                 id name  default_image_url  price           
    """
    def get(self, request):
        # 获取redis存的sku_id列表信息
        redis_conn = get_redis_connection('history')
        sku_ids = redis_conn.lrange('history_%s' % request.user.id, 0, -1)

        # 根据sku_ids列表数据，查询出商品sku信息
        skus = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(id=sku_id)
            skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })

        return JsonResponse({'code':0, 'errmsg':'ok', 'skus':skus})





































